﻿// Copyright (c) 2024 刻BITTER
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.


#pragma once

#include <cstddef>
#include <cstdint>

// #include "ioxx_debug.hpp"
#include "lipid.hpp"
#include "lipid_filter.hpp"
#include "lipid_io.hpp"

// 与PID 数据的输入 / 输出有关
namespace lipid {

    template <typename HeatSimType>
    class HeatSimSensor : public CachedSensor<float> {
       private:
        HeatSimType &_hsim;

       public:
        HeatSimSensor(HeatSimType &hsim) :
            _hsim(hsim) {}

        virtual float update() override {
            this->_current_val = _hsim.get_sensor_temp();
            return this->_current_val;
        }
    };


    template <typename HeatSimType>
    class HeatSimActuator : public IActuator<float> {
       private:
        HeatSimType &_hsim;

       public:
        HeatSimActuator(HeatSimType &hsim) :
            _hsim(hsim) {}

        virtual void set(float val) override {
            _hsim.sim(val);
        }
    };


    // template <typename R>
    class PidSignalDifferentiator : public ISensor<float> {
       public:
        using R = float;

       private:
        const PidCountCore *_pid;
        const CachedSensor<R> *_source;
        R _last_value;
        R _kd;
        R _timing_kd;

       public:
        PidSignalDifferentiator(const PidCountCore *pid, const CachedSensor<R> *source, R kd = 0, R init = 0) :
            _pid(pid), _source(source), _last_value(init) {
            //
            set_kd(kd);
        }

        virtual R update() override {
            // _IOXX_ASSERT_WITH_MESSAGE(_source != nullptr, "");
            if (_pid->sample_time_changed()) {  // 必须重新设置kd，与PID 的采样时间同步
                set_kd(_kd);
            }

            R value = _source->get();
            R d = value - _last_value;
            _last_value = value;
            return d * _kd;
        }

        /**
         * @brief 设置微分系数，如果修改了PID 采样时间，必须重新设置
         */
        void set_kd(R kd) {
            _kd = kd;
            _timing_kd = _pid->k_differential(kd);
        }

        R get_kd() const {
            return _kd;
        }

        void set_source(const CachedSensor<R> *source) {
            _source = source;
        }
    };

}  // namespace lipid